#pragma once

#include <vex/iterable/range_traits.h>
#include <iterator>

namespace vex { namespace iterable { namespace stl_interop {

    static output_range_tag convert_category(std::output_iterator_tag const &);
    static one_pass_range_tag convert_category(std::input_iterator_tag const &);
    static forward_range_tag convert_category(std::forward_iterator_tag const &);
    static bidirectional_range_tag convert_category(std::bidirectional_iterator_tag const &);
    static random_access_range_tag convert_category(std::random_access_iterator_tag const &);

    static std::output_iterator_tag convert_category(output_range_tag const &);
    static std::input_iterator_tag convert_category(one_pass_range_tag const &);
    static std::forward_iterator_tag convert_category(forward_range_tag const &);
    static std::bidirectional_iterator_tag convert_category(bidirectional_range_tag const &);
    static std::random_access_iterator_tag convert_category(random_access_range_tag const &);

    template< class TIterator, class Traits = std::iterator_traits<TIterator> >
    struct convert_iterator_traits {
        typedef Traits iterator_traits;
        typedef decltype(convert_category(typename iterator_traits::iterator_category())) category;
        typedef typename iterator_traits::reference reference;
        typedef typename iterator_traits::value_type value_type;
        typedef typename iterator_traits::pointer pointer;
    };

    template< class TRange, class Traits = range_traits<TRange> >
    struct convert_range_traits {
        typedef Traits range_traits;

        typedef typename range_traits::value_type value_type;
        typedef decltype(convert_category(typename range_traits::category())) iterator_category;
        typedef typename range_traits::reference reference;
        typedef typename range_traits::pointer pointer;
    };
}}}